Nest.js 시작하기 (<Shall we Nest.js> 밋업 1부)

author_profile남병관

*이 콘텐츠는 Nest.js Korea 1st Meetup, <Shall we Nest.js?>중, 제가 발표를 맡은 부분을 글로 정리한 것입니다.

Nest.js Korea 1st Meetup, <Shall we Nest.js?>

<Shall we Nest.js?> 밋업을 연 까닭

팀스파르타는 지난 2월부터 기술 스택을 플라스크(Flask)에서 Nest.js로 교체하는 작업을 진행하고 있는데요. Nest.js를 쓰다 보니, 이쪽 생태계가 그렇게 넓지 않다는 걸 체감하게 되더라고요. Nest.js를 사용하고 있는 우리는 그 인기가 J커브를 그리고 있다고 믿지만, ‘훨씬 더 성장 곡선이 가팔라져야 하지 않을까?’라는 생각이 들었습니다. 그래서 많은 분께 **‘우리 한번 같이 Nest.js를 써 보지 않으실래요?’**라고 제안드리는 자리를 마련하고자 밋업을 개최하게 되었습니다.

저는 크게 Nest.js 시작하기, 그리고 기술 스택을 교체하며 팀스파르타가 Nest.js를 선택한 이유, 이렇게 두 가지 주제를 가지고 이야기를 해 볼까 합니다. 제 파트는 ‘의존성 주입’이나 ‘providers’와 같은 단어에 흠칫하신 분들이 집중해서 봐 주시면 너무 좋습니다. 반대로 ‘의존성 주입은 너무 쉬운 내용인데?’, 혹은 ‘나는 익숙하진 않아도 Nest.js를 좀 써 봤어’ 하시는 분들은 다음 파트로 넘어 가시면 유익한 정보를 얻어가실 수 있을 겁니다.

목차


1. Nest.js 시작하기

Nest.js 공식 문서(Documentation) 어떠한 기술 스택이든 공식 문서에서 개요(Overview) 부분이 가장 기초 중의 기초인데요.

Nest.js 공식 문서 중 개요(Overview) 부분 Nest.js 공식 문서(https://docs.nestjs.com/) 개요에서도 저는 Controllers, Providers, Modules, Pipes. 이 네 가지만 다뤄보려고 합니다. 저와 끝까지 함께하시면 최소한 이 네 단어가 무엇을 의미하는지 알고, 적어도 사이드 프로젝트를 할 때 Nest.js를 써 먹을 수 있는 수준까지는 되실 겁니다.

Nest.js의 철학

Nest.js의 철학(Philosophy) 공식 문서에서 제일 처음 부분을 보시면 새롭게 나온 것이 어떠한 문제를 풀고 있는지를 알 수 있습니다. 그렇다면 ‘Nest.js는 무슨 문제를 풀기 위해 만들어진 거야?’라고 했을 때 **‘Nest.js는 악서버의 아키텍처(Architecture) 문제를 풀고 있는 거야’**라고 답할 수 있겠습니다.

**‘누구나 손쉽게 서버에 아키텍처를 구성해서 개발할 수 있도록 돕겠다’**는 것이 Nest.js의 기본 철학입니다. 사실 저는 이 철학을 처음 읽었을 때 ‘되게 용감하다’는 생각이 제일 먼저 들었습니다. 위에 블록 처리한 부분을 읽어 보시면 다음과 같은 이야기인데요. ‘자바스크립트(JavaScript) 진영에서, 노드(Node) 진영에서 라이브러리와 같은 툴이 많이 나오지만, 그중 그 어떠한 것도 효과적으로 중요한 아키텍처의 문제를 해결하지 못 하고 있다. 그래서 우리는 Nest.js를 만들었다.’ 이걸 읽으면서 되게 멋있으면서도 동시에 ‘무슨 자신감으로 이렇게 얘기를 하는 걸까’라는 궁금증이 생기더라고요. 이제부터 Nest.js가 아키텍처의 문제를 어떻게 풀었는지를 얘기해 보고자 합니다.

Nest.js 실행하기

위 네 줄이면 바로 서버를 띄울 수 있습니다. 그 전에 바로 Nest.js를 시작해 보고 싶은 마음이 드시죠. 시작을 함께해 보면, 위와 같이 단 4줄이면 바로 서버를 띄울 수 있습니다. 타입스크립트(TypeScript)가 적용된 Nest.js를 바로 실행하실 수 있어요. 앞으로 제가 준비한 예시를 통해서 차근차근 설명해 드릴게요.

Nest.js를 실행한 화면 위 이미지 좌측을 보시면 소스(src)라는 폴더 아래에 **컨트롤러(controller), 모듈(module), 서비스(service), 메인(main)**이 보이실 겁니다. 4줄의 명령을 순서대로 입력만 하면 이렇게 바로 서버가 뜹니다. 이렇게 뜨면서도 익스프레스(Express)나 플라스크와는 다르게 기본적으로 컨트롤러와 서비스라는 기본 아키텍처를 제공하고 있습니다.

@Module과 providers 소스를 자세히 보시면 모듈이나 프로바이더(providers)와 같은 낯선 단어들이 보이실 텐데요. ‘모듈은 대충 알 것도 같은데, 프로바이더는 대체 뭐지?’ 싶으실 수 있습니다. 보통 처음 Nest.js를 시작하시면 다들 낯설어 하세요. 이 두 가지를 설명하기 전에 먼저 우리에게 익숙한 컨트롤러부터 짚고 넘어가면 좋을 것 같습니다.

컨트롤러(Controller)

Nest.js에서 생성되는 5개의 파일 4줄의 명령을 실행하시면 위와 같은 5개의 파일이 생성됩니다. 두 번째 스펙(spec)은 테스트 파일이기 때문에 제외하고, 메인도 부트스트래핑하는 거니까 빼면 결국 컨트롤러와 모듈, 그리고 서비스가 남게 됩니다.

컨트롤러는 우리가 흔히 알고 있는 ‘그’ 컨트롤러가 맞습니다. 컨트롤러는 MVC 패턴이라든지, 스프링(Spring), 장고(Django) 등을 처음 할 때 접하게 되는 그 컨트롤러입니다. 즉 클라이언트 사이드에서 오는 HTTP 리퀘스트(request)를 받아주는 녀석인 거죠. 그러면 당연히 라우팅, 요청, 응답, 상태 코드, 헤더 등도 알아 봐야겠죠.

Nest.js의 CLI에 ‘nest -h’를 친 모습 알아보기 위해서 샘플을 생성해 보았습니다. 위 이미지는 Nest.js의 CLI(Command-line interface)인데요. **Nest.js는 기본적으로 CLI를 굉장히 적극적으로 사용합니다. ‘**nest -h’를 통해 Nest.js에서 사용할 수 있는 다양한 명령어 모음을 보여달라고 했습니다. 보시면 엄청 많은 녀석들을 생성할 수 있는 걸 알 수 있습니다. 제일 아래를 보시면 **리소스(resourse)가 ‘CRUD의 대상을 만든다(Generate a new CRUD resource)’**라고 써 있네요.

nest g resource sample 명령을 내린 화면 그래서 제일 먼저 **‘nest g resource sample’**을 실행했습니다. ‘’sample’이라는 리소스를 하나 만들어’, ‘CRUD의 단위를 하나 만들어 봐’라고 명령을 내린 건데요. 위 이미지 중간에 보시면 초록색으로 CREATE라고 쭉 나오고, UPDATE까지 된 게 보이시죠.

Nest.js는 이처럼 간단한 명령어만 입력해 주어도 기본적으로 필요한 요소들을 금방 생성해 줍니다. 앞서 함께 읽어 보았던 공식 문서의 철학에도 나와 있듯이 아키텍처를 손쉽게 사용할 수 있도록 CLI로 원하는 리소스를 바로 생성할 수 있게끔 도와주고 있는 것이죠. 그래서 보시다시피 ‘nest g resource sample’이라는 명령어 하나만 입력하면 바로 dto, entity, controller, module, service 등을 다 만들어 줍니다. 그리고 이것들이 애플리케이션 내부 전체 컨텍스트에 녹아들 수 있도록 app.module 등의 업데이트도 다 알아서 해 주죠.

라우팅 방법 다시 컨트롤러로 돌아와서 라우팅은 위와 같이 합니다. 긴말 할 필요 없이 이걸 보시면 느낌이 딱 오실 거예요. 컨트롤러라는 데코레이터(@Controller)로 이 클래스가 컨트롤러인지 아닌지 나타내줍니다.

Nest.js에는 post, get, delete와 같은 HTTP 메소드에 일대일 대응되는 기본적인 데코레이터들이 이미 다 존재합니다. 그리고 post나 put처럼 바디를 기본적으로 데이터를 가지고 오는 녀석들에 대해서는 저렇게 바디 데코레이터(@Body)를 통해 요청받은 데이터를 다 까볼 수 있도록 도와주고 있고요.

파람(@Param)을 통해서 path에 있는 파라미터들을 내가 원하는 대로 읽도록 도와주는 녀석들도 존재해요. 그리고 Dto로 입출력 정의도 이미 잘하게끔 코드가 작성되어 있습니다.

요청 객체를 위한 다양한 데코레이터 그 외에도 요청 객체를 위한 다양한 데코레이터가 존재합니다. 쿼리(Query), 헤더(Headers), 아이피(Ip) 등을 통해 내가 원하는 어떤 요청 객체에 조작이 있을 때 바로바로 즉석에서 코드를 쭉쭉 짤 수 있도록 툴 제공을 미리 많이 해 준다는 거죠. 컨트롤러는 여기까지 알아 볼게요.

프로바이더(Provider)

처음 Nest.js를 접할 때 우리를 당황 시키는(?) 프로바이더 이제 프로바이더를 알아 볼까요? Nest.js를 처음 접하실 때 제일 어려운 게 아마 프로바이더이지 않을까 생각합니다. 프로바이더를 한 문장으로 정의해 보면 ‘의존성 주입의 대상’입니다. 그러면 의존성 주입은 대체 뭘까요?

의존성 주입이란?

SampleController 코드들은 sampleService에 ‘의존’하고 있습니다. findAll이 어딘가에 구현되어 있으리라 기대하면서요. 앞서 보았던 컨트롤러 코드의 일부인데요. 이것을 보시면 컨트롤러는 sampleService의 구체적인 구현에 대해서는 전혀 알지 못하고 그냥 findALL이라는 인터페이스를 사용하고 있죠. 그저 ‘구현이 잘 되어 있겠지’라고 기대를 하면서 말이에요. 이를 우리는 **‘의존한다’**고 보통 표현합니다.

그렇다면 의존성 주입은 뭘까요. 이런 경우를 상정해 볼게요. 바로 전 컨트롤러 코드를 보시면 sampleService에 컨트롤러가 의존을 하고 있는 것을 확인하실 수 있는데요.

sampleService에 SampleBestService를 대신 주입해 줘. 그런데 어느 날 SampleService가 아니라, 생각이 좀 바뀌어서 SampleBestService를 만들었다고 가정해 보자고요. 그리고 이 녀석의 findAll, 즉 컨트롤러 코드는 한 줄도 바꾸지 않은 채로 이 findAll을 사용하고 싶다면 어떻게 해면 될까요?

위와 같이 코드가 구현되어 있다면 선언부를 다 바꿔줘야 됩니다. 만약 이렇게 코드가 구현되어 있다면 선언부를 SampleBestService로 다 수정해야 합니다. 또 생성자가 바뀌면? 또 다시 코드를 바꿔 줘야겠죠. 어딘가 불편하다는 생각이 드실 겁니다. 그래서 실제 구현대상을 주입해준다는 것이 의존성 주입의 기본 아이디어입니다.

실제 구현 대상을 ‘주입’해 준다면, 어떤 녀석을 넣어줄 것인지만 결정하면 됩니다. 추상적으로 ‘나는 이런 녀석을 만들 거야’라고 해 두고, 실제로 그 녀석의 구현은 컨트롤러가 만들어질 때 프레임워크가 주입을 해 준다는 거죠. 내가 사용하는 것의 주도권이 ‘나한텐 없다’는 얘기입니다. 이런 것을 보통 IoC(제어의 역전)라고 부르는데요. 정리해 보면, 의존성 주임의 핵심은 추상과 구현이 분리됨으로써 코드가 유연해지고, 테스트하기에도 굉장히 용이해진다는 장점이 있다는 겁니다.

의존성 주입 구현 방법

의존성 주입 구현 방법도 알아 볼게요. 위 이미지를 보시면 인젝트(@Inject)라는 데코레이터가 있는데요. 여기에 ‘SampleService’라는 토큰(token)을 넣어준 것을 확인하실 수 있습니다. 여기서 토큰이란, 내가 의존성을 주입할 대상들을 일대일로 규명하는 일종의 pk값이라고 생각하시면 됩니다.

의존성 주입 구현 방법 예시 위와 같이 해 주면 컨트롤러의 코드를 단 한 줄도 바꾸지 않고도 ‘SampleBestService’의 코드를 활용하실 수 있게 됩니다. 보시면 providers에 실제로 의존성 주입을 할 녀석들을 나열하고 있는데요. ‘SampleService’라는 토큰의 대상이 있으면, ‘SampleBestService’라는 클래스를 사용해’가 위 코드의 내용입니다. 실제 SampleService에 무엇을 넣어줄지는 모듈에서 자유롭게 바꿀 수 있습니다. 의존성 주입의 툴이 유연하고, 우리에게 굉장히 편리하게 제공해 주고 있는 것이 Nest.js의 가장 큰 장점이라고 할 수 있습니다.

이렇게 의존성 주입의 대상이 되는 녀석들을 Provider라고 합니다. 의존성 주입은 아주 간단한 방법으로 가능합니다. 의존성 주입의 대상을 프로바이더라고 하는데요. 인젝터블(@Injectable) 데코레이터를 통해 프로바이더의 역할을 부여할 수 있습니다. 즉 인젝터블 데코레이터를 붙여주면 ‘이 친구가 프로바이더야’라고 Nest.js에 알려주는 것이죠.

의존성 주입은 여기서 끝이 아니라 하나 더 조치를 취해 줘야 합니다.

의존성 주입 부분의 실제 코드 주석 실제 코드 주석에서 두 번째 문단(When injecting a provider, it must be visible within the module scope(loosely speaking, the containing module) of the class it is being injected into. ~)을 살펴 보면요. **프로바이더를 주입하려면, ‘모듈 단위에서 프로바이더라고 알려주어야 한다’**고 나와 있습니다.

모듈에서 프로바이더를 명세하는 방법 바로 적용해 보았습니다. 모듈(@Module)의 명세에 providers라는 배열 안에 의존성 주입 대상으로 삼은 것들을 넣어주시면 됩니다. 정리해 보면, 의존성 주입을 하는 방법은 인젝터블과 모듈, 이 2가지 작업만 수행하시면 자유롭게 활용하실 수 있겠죠.

모듈(Module)

모듈 코드 주석 그렇다면 이제 모듈을 살펴 볼까요.

모듈은 쉽게 말해 큼지막하게 묶은 것입니다. 모듈은 쉽게 말해 큼직큼직하게 묶은 거예요. 사실 여러분 모두가 이렇게 개발을 해 오고 계실 텐데요. 애플리케이션이라고 함은 Users, Orders, 그리고 Chat과 그 하위 기능들의 묶음 등으로 구성되어 있는 거죠.

모듈의 기본적인 명세 4가지 그렇다면 모듈이라는 묶음에서 나에게 필요한 것이 무엇이고, 각각은 무엇을 제공하는지 알아 볼까요. 모듈에는 기본적으로 네 가지의 명세가 존재합니다.

1. imports : 갖다 쓸 모듈

2. controllers : 외부 노출할 것

3. providers : 의존성 주입할 것

4. exports : 다른 것들이 쓸 것

덧붙여 설명해 보면, imports는 다음과 같습니다. 어떤 특정 모듈이 다른 모듈에 의존하는, 즉 모듈간 상호의존관계가 있을 수도 있는데요. 그 때 ‘A 모듈은 B 모듈에 의존하고 있어’라는 것을 imports를 활용해 명시해 줄 수 있습니다. controllers는 앞에서 컨트롤러를 설명했으니 패스하겠습니다. providers는 내 모듈 내에서 기본적으로 의존성 주입의 대상이 된 녀석들을 나열한 거고요. 마지막으로 exports는 다른 모듈이 나(모듈)를 import했을 때 내가 기본적으로 제공해 줄 것들을 말합니다.

루트 모듈(Root Module)

루트 모듈은 이렇게 구성됩니다. 다시 윗 단계로 올라와 보면, 그래서 루트모델은 이렇게 구성이 됩니다. 모듈 트리 구조를 보시면, 모든 모듈은 최종적으로 애플리케이션 모듈을 향하고 있는 것을 보실 수 있는데요. 애플리케이션 모듈이 루트에 있고, 이것을 토대로 트리 형태로 의존이 이뤄진다고 생각해 주시면 될 것 같습니다.

만약 위 이미지 속 imports에 있는 SampleModule을 지우면 어떻게 될까요? 아무리 여러분이 SampleModule의 코드를 열심히 짜더라도, Nest.js는 알 수가 없겠죠. 그냥 없는 거나 마찬가지가 되는 겁니다.

이제 계속 Nest.js를 사용하시다 보면 다른 모듈에 비해 사용도가 높은 모듈을 글로벌 모듈로 만들 수 있는 방법을 생각해 보게 되실 텐데요.

글로벌 모듈 구현 방법 여러분이 원하시는 대로 글로벌 모듈을 구현할 수 있습니다. 심지어 아주 간단한 방법으로 말이죠. 모듈 위에 @Global()만 붙여주시면 됩니다. 글로벌 데코레이터만 붙여주시면 글로벌 프로바이더를 만들 수 있습니다. 하지만 조심해서 사용하셔야 해요. 글로벌로 만든다는 것은 import하지 않아도 손쉽게 갖다 쓸 수 있다는 것이지만, 동시에 모듈의 명세를 깨뜨리는 것이 되기 때문에 제한적으로 사용하시는 게 좋습니다.

파이프(Pipe)

입출력의 명세를 정의하고, validation을 체크해 주는 역할을 담당하는 파이프(pipe) 코드 짜는 것만큼이나 중요한 게 있죠. 입출력의 명세를 잘 정의하고, 그에 맞게 validation을 해주는 건데요. 그 역할을 파이프가 담당하고 있습니다. 기본적으로 Input을 원하는 형태로 바꾸거나(Transformation), 혹은 타당성을 검증(Validation)합니다.

Nest.js가 제공하는 파이프 리스트 Nest.js는 out-of-the-box를 지향하기 때문에 이미 제공하고 있는 파이프들이 있습니다. 위 리스트는 Nest.js의 common 패키지에 들어가 있는 파이프들인데요. 때문에 적극적으로 사용해 주시면 좋겠죠?

파이프 구현 방법

id를 number로 바꾸기 위해 ParseIntPipe를 사용해 준 모습 파이프는 이렇게 사용하실 수 있습니다. Nest.js가 제공하고 있는 파이프에 코드를 조금만 덧붙여 주시면 바로 사용이 가능합니다. 저는 예시로 파라미터에 id로 오는 것을 number 형태로 바꾸기 위해 ‘ParseIntPipe’를 사용해 보았습니다. 이렇게 콤마와 함께 한 줄만 넣어주면 바로 사용할 수 있습니다.

Validation failed 만약 number가 적절하지 않은 형태로 들어온다면 이렇게 “Validation failed”를 알아서 보내 주고요.

파이프 응답코드(statusCode) 변경하기

‘400을 NOT_ACCEPTABLE로 바꿔줘’ 당연히 파이프의 응답코드(statusCode)도 커스터마이징 할 수 있습니다. 400으로 받던 것을 ‘NOT_ACCEPTABLE’로 받고 싶다고 코드를 짜 보았습니다.

Schema-based validation도 가능합니다. 방금처럼 패스(path)나 파람(@Param)에만 제한이 있지 않습니다. 많이들 Dto를 사용하시는데요. 특히, Node.js에서 개발을 많이 해보신 분들은 class-validator를 많이 사용하실 텐데, @IsString, @IsInt 등과 같은 형태로 class-validator와 조합하면 굉장히 편하게 사용하실 수 있습니다.

바로 위 두 번째 이미지에서 ValidationPipe는 제가 커스텀해 본 것입니다. 어떻게 커스텀 파이프를 만드는지 알려드리며 첫 번째 주제를 마무리해 보려 합니다.

커스텀 파이프 만드는 방법 커스텀 파이프는 위와 같이 만들 수 있습니다. 저는 Dto를 name, age, city가 들어오도록 했습니다. 예를 들어, name은 남병관, city는 서울, age는 abc 이렇게 보냈다고 했을 때 어떻게 되는지를 봐 볼까요. 기본적으로 여기 transform, PipeTransformimplements하시면 되고요. transform이라는 메소드를 구현해 주시면 커스텀 파이프가 알아서 작동하게 됩니다.

파라미터로는 valuemetatype이 있습니다. 들어오는 것들은 value에 기본적으로 JSON 형태로 들어옵니다. 중간에 plainToInstance라는 게 보이실 거예요. 이건 Nest.js에서 기본적으로 제공되는 것으로, plainToInstance를 쓰시면 여러분이 기본적으로 설정한 것에 알맞게 변화시켜 줍니다. 그 후에 IsString, IsInt 등으로 유효성을 체크하고요. 예시로 제가 나이에 abc를 넣었죠? 맞지 않기 때문에 에러를 띄우게 됩니다.

여기까지 Nest.js의 기본을 알아 보았습니다. 여기까지만 잘 숙지하시면 기본적인 프로젝트 진행에는 전혀 무리가 없을 것으로 생각합니다. 이쯤에서 한 번 더 “Shall We Nest.js?” 제안드려 봅니다.

이제 저희 팀스파르타가 기술 스택을 교체하면서 Nest.js를 선택한 이유로 넘어가 볼게요.

2. 기술 스택을 교체하며 Nest.js를 선택한 이유

코드에 따라 지수적으로 늘어나는 복잡도 팀스파르타가 서비스를 출시한 지 2년 정도가 됐는데요. 그 동안은 파이썬 플라스크를 쓰다가 지난 2월에 Nest.js로 교체를 결정했습니다. 왜 수많은 기술 스택 중에서 Nest.js를 택하게 됐는지, 여러분께 간단하게 스토리를 들려드리면 좋을 것 같아 이 주제를 가져와 보았습니다.

2년 동안 플라스크를 쓰면서 내부 의존성은 위 이미지처럼 말 그대로 big ball of mud 상태였습니다. 여러분이 보시기에 이 형태의 가장 큰 문제가 뭐라고 생각하시나요? 저는 저 큰 원의 테두리에 단 하나의 점만 추가해도 관계를 맺어야 되는 대상이 너무 많이 늘어난다는 게 가장 큰 문제라고 생각했습니다. 즉 코드 양의 증가에 따른 코드의 복잡도가 지수적으로 증가하게 된다는 거죠. 처음에는 안고 갈 수 있었지만, 점차 회사의 규모가 커지고, 서비스가 커지면서 이를 해결해야겠다는 생각이 확고해 지더라고요.

어떻게 하면 로그 스케일로, 혹은 최소한 선형적으로 복잡도가 증가할 수 있을까? **‘어떻게 하면 로그 스케일로, 혹은 최소한 직선 형태로 복잡도가 증가할 수 있을까?’**를 엄청 고민했습니다. 파이썬 플라스크는 익스프레스와 굉장히 유사해서 아키텍처를 강제하지 않죠. 그래서 저희도 일반적인 레이어드 아키텍처를 가져 왔는데요. 그러다 보니까 복잡도가 너무 치솟는 거예요. 서비스는 뚱뚱해지고, 서비스간 상호의존도도 점점 늘어나면서 통제가 잘 안 되고 있다고 느꼈습니다. ‘어떻게 통제할 수 있을까?‘라는 생각을 해 보니, 이게 사실은 어떻게 보면 일종의 그래프더라고요.

얽혀 있는 저 상호 의존도를 트리 형태로 바꿀 수 있다면? 우리 서비스의 복잡도를 트리 형태로 바꿀 수 있다면, 즉 **복잡도가 트리의 높이가 된다면 통제가 가능하지 않을까?**로 생각이 도달했습니다.

클린 아키텍처 그러면서 동시에 든 생각은 이거였습니다. ‘아, 이래서 클린 아키텍처가 나왔구나’ 싶더라고요. ‘내가 원하는 대로 의존성을 통제하기 위해 클린 아키텍처가 필요한 거구나’ 생각이 들었고, ‘어떻게 이것을 구현할 수 있을까?’에 대한 해답의 실마리로 ‘의존성 역전’을 떠올렸습니다.

헥사고날 아키텍처(Hexagonal Architecture) 그때 한창 의존성을 역전하고 통제할 수 있는 다양한 방법을 좀 검토를 해 봤고요. 일단 당시에 찾은 방법은 **헥사고날 아키테처(Hexagonal Architecture)**였습니다. ‘도메인에 조금 더 신경을 쓰게 되고, 적절한 부분에서 적절히 의존성이 역전되기 때문에 코드의 복잡도가 최소한 지수적으로 증가하지는 않겠다’라는 깨달음을 얻었던 것 같아요. 이것은 다음 번에 자세히 다루도록 하겠습니다.

그래서 이제 ‘어떤 것을 구현체로 쓰지?’를 고민했고, 결국 의존성 주입을 기본적으로 프레임워크에서 제공하는 것을 사용해 써야겠더라고요. 우리나라 서버 개발의 대명사라고 할 수 있는 스프링은 현실적인 문제에 부딪혔습니다. 우선, 당시 스프링은 저희 개발팀에서 저만 할 수 있었고요. 당시에는 팀 내 개발자도 적었고, 새롭게 배우는 데에 복잡도가 비교적 높아서 교육 비용이 너무 높다는 문제도 있었습니다. 비즈니스에서 속도가 핵심인데, 스프링은 안 될 것 같더라고요.

그래서 다른 대안을 찾아 보다가 Nest.js를 발견하게 됐습니다. 일단 가장 큰 매력은 의존성 역전의 도구를 굉장히 편하게 사용할 수 있다는 거였습니다. 게다가 타입스크립트(TypeScript)와 노드(Node) 진영의 풍부한 생태계에 발을 디디고 있다는 것도 굉장한 매력이었죠. 그래서 저희는 Nest.js를 사용하게 됐고, 레거시를 대체하는 작업을 진행 중에 있습니다. 물론 신규 프로덕트는 다 Nest.js로 개발하고 있고요. ‘앞으로 2년은 문제 없지 않을까?’라는 생각을 하고 있습니다.

이 정도로 저희가 Nest.js로 기술 스택을 교체하게 된 이유를 얘기해 볼 수 있을 것 같아요. 어떠셨나요? 여러분도 Nest.js를 적극 사용해 보고 싶지 않으신가요? 다음 시간에는 헥사고날 아키텍처에 대해 자세히 이야기해 보려고 합니다. 좀 더 심화 버전의 이야기가 궁금하시다면, 꼭 다음 글도 읽어 봐 주세요. 감사합니다.

Copyright ©2022 TEAMSPARTA. All rights reserved.